﻿//////////////////////////////////////////////////////////////////////////////
//
//  Copyright © 1998-2024 Glodon Company Limited.  All rights reserved.
//
//  Use of this software is subject to the terms of the Glodon license
//  agreement provided at the time of installation or download, or which
//  otherwise accompanies this software in either electronic or hard copy form.  
//
//////////////////////////////////////////////////////////////////////////////

#pragma once
#include "GmepModelInterface.h"
#include "Vector3d.h"
#include "IMepCurve.h"
#include "IConnector.h"
#include "IMepElement.h"
#include "IMepDevice.h"
#include "IGmepConstDefinition.h"
#include "IMepFitting.h"
#include "IDocument.h"
#include "WeakPtr.h"
#include "ElementId.h"

namespace AlgorithmMep
{
    class SearchSystem; 
   
    enum class SearchSystemFilter;
    
    class GMEP_MODEL_INTERFACE_EXPORT SearchNode
    {
    public:
        SearchNode();        
        ~SearchNode();
        SearchNode(SearchSystem* searchSystem, const gmep::IMepElement* element, const gcmp::Vector3d &pickPoint,
            gcmp::IDocument* doc, const gcmp::ElementId &eleId);
        SearchNode(SearchSystem* searchSystem, gcmp::IDocument* doc);        
    private:        
        /*typedef std::function<gmep::IMepElement*(gmep::IConnector* connector
            , SearchSystemFilter searchSystemFilter)> *CallbackFun;*/

        typedef const gmep::IMepElement* (*CallbackFun)(const gmep::IConnector* connector
            , SearchSystemFilter searchSystemFilter, bool isIgnoreSystem);


    public:
        void SearchNext();
        void SearchNext(CallbackFun searchNextElementWhenNoConnected, SearchSystemFilter searchSystemFilter);
        static const gmep::IMepElement* GetNextElementByPosition(const gmep::IConnector* connector,
            SearchSystemFilter searchSystemFilter, bool isIgnoreSystem = false);
        static const gmep::IMepElement* GetElementByPoint(gcmp::IDocument* doc, gcmp::Vector3d point, const gmep::IConnector* connector,
            SearchSystemFilter searchSystemFilter, bool isIgnoreSystem = false);
        //处理链接文件搜索，暂时不处理        
        static const gmep::IMepElement* GetElementByPoint(gcmp::IDocument* doc, gcmp::Vector3d point,
            std::wstring systemName, gcmp::ElementId exceptId, bool isIgnoreSystem = false);
        static const gmep::IMepElement* GetElementByPoint(gcmp::IDocument* doc, gcmp::Vector3d point, gcmp::ElementId exceptId);
        static const gmep::IMepElement* GetElementByPoint(gcmp::IDocument* doc, gcmp::Vector3d point,
            gmep::MEPSystemClassification systemClass, gcmp::ElementId exceptId);
        static const gmep::IMepElement* GetNextElementInOtherDocument(const gmep::IConnector* connector, SearchSystemFilter searchSystemFilter);
        static std::vector<const gmep::IMepCurve*> GetElements(gcmp::IDocument* doc, gcmp::Vector3d searchPoint, double searchBoxLength);
        static std::vector<const gmep::IMepDevice*> GetDeviceElements(gcmp::IDocument* doc, gcmp::Vector3d searchPoint, double searchBoxLength);
        static std::vector<const gmep::IMepFitting*> GetFittingElements(gcmp::IDocument* doc, gcmp::Vector3d searchPoint, double searchBoxLength);

        static std::vector<const gmep::IMepCurve*> ExceptElements(std::vector<const gmep::IMepCurve*> curves, gcmp::ElementId exceptId
            , std::wstring sysName, gmep::MEPSystemClassification systemClass, bool isTrimEndNumber = false, bool isIgnoreSystem = false);
        static std::vector<const gmep::IMepDevice*> ExceptDeviceElements(std::vector<const gmep::IMepDevice*> curves, gcmp::ElementId exceptId, std::wstring sysName, gmep::MEPSystemClassification systemClass, bool isTrimEndNumber = false);
        static std::vector<const gmep::IMepFitting*> ExceptFittingElements(std::vector<const gmep::IMepFitting*> curves, gcmp::ElementId exceptId, std::wstring sysName, gmep::MEPSystemClassification systemClass, bool isTrimEndNumber = false);

        static std::vector<const gmep::IConnector*> GetAllMepConnectors(std::vector<const gmep::IMepCurve*> eles, bool isClass = false, gmep::MEPSystemClassification systemClass = gmep::MEPSystemClassification::UndefinedSystemClassification);
        static std::vector<const gmep::IConnector*> GetAllDeviceConnectors(std::vector<const gmep::IMepDevice*> eles, bool isClass = false, gmep::MEPSystemClassification systemClass = gmep::MEPSystemClassification::UndefinedSystemClassification);
        static std::vector<const gmep::IConnector*> GetAllFittingConnectors(std::vector<const gmep::IMepFitting*> eles, bool isClass = false, gmep::MEPSystemClassification systemClass = gmep::MEPSystemClassification::UndefinedSystemClassification);

        SearchNode* GetNextNode(const gmep::IConnector* connector, SearchSystemFilter searchSystemFilter, CallbackFun searchNextElementWhenNoConnected, bool& isForbidden);
        void SetNextNodePrevious(const gmep::IConnector* connector, SearchNode* nextNode);
        bool IsSidePreviousOther(const gmep::IConnector* connector, std::vector<const gmep::IConnector*> SidePreviousOther);

        int IsDfsOrder(const gmep::IMepElement*  nextElem);
        /*static std::vector<gmep::IConnector*> GetAllInstanceConnectors(const std::vector<gmep::IMepInstance*> eles, bool isClass = false, gmep::MEPSystemClassification systemClass = gmep::MEPSystemClassification::UndefinedSystemClassification);*/
        const gmep::IMepElement* GetNextElementByConnect(const gmep::IConnector* connector);
        bool isDuctTap(const gmep::IMepElement* ele,const gmep::IConnector* conn);
        static std::wstring TrimEndNumber(std::wstring sysName);
        const gmep::IMepElement* GetMepElement();
    public:
        gcmp::Vector3d searchPoint;
        bool IsLoop;
        bool IsTap;
        bool m_SplitFlow = true;//分流
        bool m_IsBranch = false;
        
        SearchSystem* searchNodeSystem = nullptr;
        //gmep::IMepElement* mepNodeElement = nullptr;
        gcmp::ElementId mepNodeElementId;
        //处理出现环路的时候需要将环形进行并流处理 shenchen  2021-4-9
        SearchNode* PreviousNode = nullptr;
        gcmp::WeakPtr<const gmep::IConnector> PreviousConn;
        SearchNode* BranchPreviousNode = nullptr;
        gcmp::WeakPtr<const gmep::IConnector> BranchPreviousConn;
        SearchNode* Branch2PreviousNode = nullptr;
        gcmp::WeakPtr<const gmep::IConnector> Branch2PreviousConn;
        std::vector<SearchNode*> BranchSidePreviousNode;
        std::vector<gcmp::WeakPtr<const gmep::IConnector>> SidePreviousOther;
        std::vector<SearchNode*> SubPreviousNodes;
        std::vector<gcmp::WeakPtr<const gmep::IConnector>> SubPreviousConns;

        int ConnectorCount = 0;
        std::vector<gcmp::WeakPtr<const gmep::IConnector>> Connectors;
        gcmp::WeakPtr<const gmep::IConnector> In;
        gcmp::WeakPtr<const gmep::IConnector> Out;
        gcmp::WeakPtr<const gmep::IConnector> Side;
        gcmp::WeakPtr<const gmep::IConnector> Side2;
        std::vector<gcmp::WeakPtr<const gmep::IConnector>> SideOther;
        SearchNode* NextNode = nullptr;
        SearchNode* BranchNode = nullptr;
        SearchNode* Branch2Node = nullptr;
        std::vector<SearchNode*> BranchSideNode;
        std::vector<SearchNode*> SubNodes;
        std::vector<gcmp::WeakPtr<const gmep::IConnector>> SubConns;
        SearchNode* nxtNode = nullptr;
        void Init(const gcmp::Vector3d &inPoint);
    private:
        gcmp::IDocument* m_pdoc = nullptr;
        bool m_isDevice = false;
        bool m_isFitting = false;
        
    };
}